#ifndef __SVD_H__
#define __SVD_H__

#include<vector>
#include<ext/hash_map>

using namespace std;
using __gnu_cxx::hash_map;

typedef vector<double> row_t;
typedef hash_map<int, row_t> matrix_t;

struct Itemscore
{
	int item;
	double score;
};

class SVDTrainer
{
	public:
		SVDTrainer();
		SVDTrainer(hash_map<int, vector<int> > &real_map, const int dimension, const double k1, const double k2);
		~SVDTrainer();
		void train(hash_map<int, vector<int> > real_map, const double learning_rate, const int max_step);
		vector<Itemscore> yield_item(int item, int size);
		void init(hash_map<int, vector<int> > &i2w, hash_map<int, vector<int> > &w2i);
	private:
		matrix_t U, M;
		int xmax, ymax, dim;
		double l_rate, kx, ky;
		hash_map<int, int> key2x, key2y;
		double mult_ij(matrix_t& U, matrix_t& M, const int i, const int j);
		double RMSE(hash_map<int, vector<int> > &real_map, matrix_t& U, matrix_t& M);
		row_t gradient(const int i, const int j, const double k, matrix_t &P, matrix_t &Q);
		void update(matrix_t &P, row_t &Q, const int i);
};

#endif
